<?php
class UpgradePage extends MemberPage {
	private static $default_parent = 'MemberPackagePage';
	
    private static $db = array();

    private static $has_one = array();

}

class UpgradePage_Controller extends MemberPage_Controller {

    /**
     * An array of actions that can be accessed via a request. Each array element
     * should be an action name, and the
     * permissions or conditions required to allow the user to access it.
     *
     * <code>
     * array (
     *     'action', // anyone can access this action
     *     'action' => true, // same as above
     *     'action' => 'ADMIN', // you must have ADMIN permissions to access this
     * action
     *     'action' => '->checkAction' // you can only access this action if
     * $this->checkAction() returns true
     * );
     * </code>
     *
     * @var array
     */
    private static $allowed_actions = array (
        'PackageForm',
        'upgrade',
        'UpgradeForm',
        'confirm',
        'ConfirmForm',
        'complete'
    );

    public function index(){
    	$confirm_msg = _t('UpgradePage.CONFIRM_MSG', 'Are you sure you want to purchase package');
		$js = <<<JS
			(function($) {
				$('.buy').on('click', function(e) {
					e.preventDefault();
					var tr = $(this).parents('tr');
					var confirm_msg = '$confirm_msg ' + tr.find('.package').text() + ' ' + tr.find('.price').find('select.dropdown option:selected').text() + '?';
  					if (confirm(confirm_msg)){
  						window.location.href = $(this).data('link') + '/' + tr.find('.price').find('select.dropdown').val();
         				return true;
      				}
      				return false;
				});
			})(jQuery);
JS;
		Requirements::customScript($js, 'UpgradePackage');
		
        return array('Form' => $this->PackageForm());
    }
	
	public function PackageForm(){
		$content = '<div class="table-responsive"><table class="table table-striped table-hover">';
		$content .= sprintf('<thead><tr><th>%s</th><th class="text-right" width="200px">%s</th><th></th></tr></thead>', _t('UpgradePage.PACKAGE', 'Package'), _t('UpgradePage.PRICE', 'Price'));
		$content .= '<tbody>';
		$packages = Package::get()->filter('Type', 'Upgrade')->filter('IsActive', 1);
		$groups = $this->CurrentMember()->Groups()->getIDList();
		foreach($packages as $package){
			if($package->RestrictGroups()->byIDs($groups)->count()){
				continue;
			}
			
			$price_list = array();
			foreach($package->Prices() as $price){
				$price_list[$price->ID] = $price->dbObject('Price')->Nice();
			}
			if(!sizeof($price_list)) continue;
			$price_field = DropdownField::create(sprintf('Price%s', $package->ID), '', $price_list)->setAttribute('style', 'width: 200px !important')->forTemplate();
			$content .= sprintf('<tr><td class="package">%s</td><td class="text-right price" width="200px">%s</td><td class="text-right"><a href="javascript: void(0);" data-link="%s" class="btn btn-primary buy">%s</a></td></tr>', $package->Title, $price_field, Controller::join_links($this->Link('upgrade'), $package->ID), _t('UpgradePage.BUTTONUPGRADE', 'Upgrade'));
		}
		$content .= '</tbody>';
		$content .= '</table></div>';
		$fields = FieldList::create(
			LiteralField::create('Package', $content)
		);
		
		$actions = FieldList::create();
		
		return Form::create($this, 'PackageForm', $fields, $actions);
	}
	
	public function upgrade(){
		return array('Form' => $this->UpgradeForm());
	}
    
    public function UpgradeForm(){
    	$package_title = _t('UpgradePage.UNKNOWN_PACKAGE', "Unknown member package");
		$package = Package::get()->filter('Type', 'Upgrade')->filter('IsActive', 1)->byID((int)$this->request->param('ID'));
		if($package && !$package->RestrictGroups()->byIDs($this->CurrentMember()->Groups()->getIDList())->count()){
			if($price = $package->Prices()->byID((int)$this->request->param('OtherID'))){
				$package_title = sprintf('%s - %s', $package->Title, $price->dbObject('Price')->Nice());
			}
		}
		
        $fields = FieldList::create(
        	HiddenField::create('PackageID', 'PackageID', $this->request->param('ID')),
        	HiddenField::create('PriceID', 'PriceID', $this->request->param('OtherID')),
        	HtmlEditorField_Readonly::create('Package', _t('UpgradePage.PACKAGE', 'Package'), $package_title),
            CustomTeamMemberField::create('Member', _t('UpgradePage.USERNAME', 'Username'))->setMemberID($this->CurrentMember()->ID)->setIncludeUpline(false)
        );
		
		$upgrade_type = array();
		if($this->CurrentMember()->AllowUpgradeFree){
			$upgrade_type['Free'] = _t('UpgradePage.UPGRADE_FREE', 'Upgrade without payment and bv but got invest program');
		}

		if($this->CurrentMember()->AllowUpgradeWithoutPayment){
			$upgrade_type['WithoutPayment'] = _t('UpgradePage.UPGRADE_WITHOUT_PAYMENT', 'Upgrade without payment but got bv');
		}

		if(sizeof($upgrade_type)){
			$fields->insertBefore(DropdownField::create('UpgradeType', _t('UpgradePage.UPGRADE_TYPE', 'Upgrade Type'))->setSource($upgrade_type), 'Package');
		}
		else{
			$fields->push(HiddenField::create('UpgradeType', _t('UpgradePage.UPGRADE_TYPE', 'Upgrade Type'), 'Normal'));
		}
			
        $actions = FieldList::create(
            FormAction::create('doUpgrade', _t('UpgradePage.BUTTONUPGRADE', 'Upgrade'))
        );
        
        $validators = Upgrade_Validator::create('PackageID', 'PriceID', 'Member');
        
        return Form::create($this, 'UpgradeForm', $fields, $actions, $validators);
    }
    
    public function doUpgrade($data, $form){
        try {
            $member = Distributor::get_obj_by_username($data['Member']['username']);
            $form->saveInto($member);
            Session::set('UpgradeMember', $member);
            return $this->redirect($this->Link('confirm'));
        }
        catch(ValidationException $e) {
            SS_Log::log(new Exception(print_r($e->getMessage(), true)), SS_Log::NOTICE);
            $form->sessionMessage($e->getResult()->message(), 'error');
        }
        return $this->redirectBack();
    }

	public function confirm(){
		if(Session::get('UpgradeMember')){
			return array('Form' => $this->ConfirmForm()->loadDataFrom(Session::get('UpgradeMember')));
		}
		
		return $this->redirect($this->Link());
	}
	
	public function ConfirmForm(){
		if(!Session::get('UpgradeMember')){
			return $this->redirect($this->Link());
		}
		
		$package_title = _t('UpgradePage.UNKNOWN_PACKAGE', "Unknown member package");
		$package_price = 0;
		$package = Package::get()->filter('Type', 'Upgrade')->filter('IsActive', 1)->byID((int)Session::get('UpgradeMember')->PackageID);
		if($package && !$package->RestrictGroups()->byIDs($this->CurrentMember()->Groups()->getIDList())->count()){
			if($price = $package->Prices()->byID((int)Session::get('UpgradeMember')->PriceID)){
				$package_price = $price->Price;
				$package_title = sprintf('%s - %s', $package->Title, $price->dbObject('Price')->Nice());
			}
		}
		
		if($package_price <= 0){
			return $this->redirect($this->Link());
		}
		
        $fields = FieldList::create(
        	HiddenField::create('PackageID', 'PackageID', $this->request->param('ID')),
            HiddenField::create('PriceID', 'PriceID', $this->request->param('OtherID')),
            HiddenField::create('UpgradeType', _t('UpgradePage.UPGRADE_TYPE', 'Upgrade Type')),
        	HtmlEditorField_Readonly::create('Package', _t('UpgradePage.PACKAGE', 'Package'), $package_title),
            CustomTeamMemberField::create('Member', _t('UpgradePage.USERNAME', 'Username'))->setMemberID($this->CurrentMember()->ID)->setIncludeUpline(false)
        );
		
		foreach($fields as $field){
			if($field->class == 'LiteralField'){
				continue;
			}
			
			$field = $field->performReadonlyTransformation();
			if($field->hasMethod('setIncludeHiddenField')){
				$field->setIncludeHiddenField(true);
			}
			$fields->push($field);
		}
		
		if(Session::get('UpgradeMember')->UpgradeType == 'WithoutPayment' || Session::get('UpgradeMember')->UpgradeType == 'Free'){
			$validators = Upgrade_Validator::create('PackageID', 'PriceID', 'Member');
		}
		else{
			$supported_methods = Payment::get_supported_methods();
	        if(sizeof($supported_methods)){
	            foreach($supported_methods as $method => $title){
	                if($method != 'PurchasePlusCashPayment'){
	                    Payment::remove_supported_methods($method);
	                }
	            }
	        }
	
	        $fields = Payment::combined_form_fields($fields, $this->CurrentMember()->ID, $package_price);
			
			$validators = UpgradePayment_Validator::create('PackageID', 'PriceID', 'Member');
		}
			
        $actions = FieldList::create(
            FormAction::create('doConfirm', _t('UpgradePage.BUTTONCONFIRMUPGRADE', 'Confirm Upgrade'))
        );
        
        return Form::create($this, 'ConfirmForm', $fields, $actions, $validators);
    }
	
	public function doConfirm($data, $form){
        try {
            DB::getConn()->transactionStart();
            $member = Session::get('UpgradeMember');
			
			$package = Package::get_by_id('Package', Session::get('UpgradeMember')->PackageID);
			$price = $package->Prices()->byID(Session::get('UpgradeMember')->PriceID);
			
			if($member->UpgradeType == 'WithoutPayment'){
				$billing_address = PackageBillingAddress::create()
				->setField('Name', $this->CurrentMember()->getName())
				->setField('Contact', $this->CurrentMember()->Mobile)
				->setField('Email', $this->CurrentMember()->Email)
				->setField('Address', $this->CurrentMember()->Address)
				->setField('Suburb', $this->CurrentMember()->Suburb)
				->setField('State', $this->CurrentMember()->State)
				->setField('Postcode', $this->CurrentMember()->Postcode)
				->setField('Country', $this->CurrentMember()->Country);
				$billing_address->write();
				
				$order = OrderPackage::create()
				->setField('Type', $package->Type)
				->setField('Title', $package->Title)
				->setField('Price', $price->Price)
				->setField('BV', $price->BV)
				->setField('PackageID', $package->ID)
				->setField('UpgradeGroupID', $package->UpgradeGroupID)
				->setField('BillingAddressID', $billing_address->ID)
				->setField('MemberID', $member->ID)
				->setField('PaidByID', $this->CurrentMember()->ID)
				->setField('SoldByID', $member->Sponsor()->ID);
				$order->write();
				
				OrderPackage::update_status($order->ID, 'Fully Paid');
			}
			else if($member->UpgradeType == 'Free'){
				if($package->UpgradeGroupID) {
	                $member->Groups()->add($package->UpgradeGroupID);
					$member->setField('MaxPayout', $price->Price * 3)->write();
				}
				
				$setting_table = Config::inst()->get('InvestProgram', 'setting_table');
				$current_setting = $setting_table[$package->UpgradeGroup()->Code];
				$next_payout = date("Y-m-d", strtotime("+1 day", time()));
				$dw = date("w", strtotime($next_payout));
				if($dw == 0){
					$next_payout = strtotime("+1 day", strtotime($next_payout));
				}
				else if($dw == 6){
					$next_payout = strtotime("+2 day", strtotime($next_payout));
				}
				$id = InvestProgram::create()
				->setField('Percentage', $current_setting['percentage'])
				->setField('MaxDay', $current_setting['max_day'])
				->setField('NextPayout', $next_payout)
				->setField('MemberID', $member->ID)
				->setField('GroupID', $package->UpgradeGroupID)
				->write();
			} 
			else {
				$receipt = Receipt::create()
				->setField('TotalAmount', $data['TotalAmount'])
				->setField('Currency', SiteCurrencyConfig::current_site_currency())
				->setField('MemberID', $this->CurrentMember()->ID)
				->updateTransactionType('UPGRADE');
				$receipt->write();
				$payment = $receipt->addPayment($data['Payment'], $data);
				
				$billing_address = PackageBillingAddress::create()
				->setField('Name', $this->CurrentMember()->getName())
				->setField('Contact', $this->CurrentMember()->Mobile)
				->setField('Email', $this->CurrentMember()->Email)
				->setField('Address', $this->CurrentMember()->Address)
				->setField('Suburb', $this->CurrentMember()->Suburb)
				->setField('State', $this->CurrentMember()->State)
				->setField('Postcode', $this->CurrentMember()->Postcode)
				->setField('Country', $this->CurrentMember()->Country);
				$billing_address->write();
				
				$order = OrderPackage::create()
				->setField('Type', $package->Type)
				->setField('Title', $package->Title)
				->setField('Price', $price->Price)
				->setField('BV', $price->BV)
				->setField('PackageID', $package->ID)
				->setField('UpgradeGroupID', $package->UpgradeGroupID)
				->setField('BillingAddressID', $billing_address->ID)
				->setField('PaymentReceiptID', $receipt->ID)
				->setField('MemberID', $member->ID)
				->setField('PaidByID', $this->CurrentMember()->ID)
				->setField('SoldByID', $member->Sponsor()->ID);
				$order->write();
			}
			
			Session::clear('UpgradeMember');
            Session::set('Upgraded', Member::get()->byID($member->ID));
            DB::getConn()->transactionEnd();
			
			if($member->UpgradeType == 'Free' || $member->UpgradeType == 'WithoutPayment'){
				return $this->redirect($this->Link('complete'));
			}
			else{
				return $this->redirect($payment->ProcessLink());
			}
        }
        catch(ValidationException $e) {
            DB::getConn()->transactionRollback();
            SS_Log::log(new Exception(print_r($e->getMessage(), true)), SS_Log::NOTICE);
            $form->sessionMessage($e->getResult()->message(), 'error');
        }
        return $this->redirectBack();
    }
    
    public function complete(){
        if(Session::get('Upgraded')){
            $member = Session::get('Upgraded');
            Session::clear('Upgraded');
            return array(
                'Member' => $member
            );
        }
        
        return $this->redirect($this->Link());
    }
}

class Upgrade_Validator extends RequiredFields {

    protected $customRequired = array();

    /**
     * Constructor
     */
    public function __construct() {
        $required = func_get_args();
        if(isset($required[0]) && is_array($required[0])) {
            $required = $required[0];
        }
        $required = array_merge($required, $this->customRequired);

        parent::__construct($required);
    }

    /**
     * Check if the submitted list data is valid (server-side)
     *
     * @param array $data Submitted data
     * @return bool Returns TRUE if the submitted data is valid, otherwise
     *              FALSE.
     */
    function php($data) {
        $valid = parent::php($data);

		$current_member = Controller::curr()->CurrentMember();
		$obj = Sponsor::get()->find('MemberID', $current_member->ID);
		$member_id = Distributor::get_id_by_username($data['Member']);
    	$result = Sponsor::get()
    	->filter('NLeft:GreaterThanOrEqual', (int)$obj->NLeft)
    	->filter('NRight:LessThanOrEqual', (int)$obj->NRight)
		->filter('MemberID', (int)$member_id)->count();
		
		if(!$result){
        	$obj = Placement::get()->find('MemberID', $current_member->ID);
			$result = Placement::get()
	    	->filter('NLeft:GreaterThanOrEqual', (int)$obj->NLeft)
	    	->filter('NRight:LessThanOrEqual', (int)$obj->NRight)
			->filter('MemberID', (int)$member_id)->count();
        }
		
		if($result){
			$member = Member::get()->find('Username', $data['Member']);
			if(($data['UpgradeType'] == 'WithoutPayment' && !$current_member->AllowUpgradeWithoutPayment) || ($data['UpgradeType'] == 'Free' && !$current_member->AllowUpgradeFree)){
				$result = false;
			}
		}
		
        if(!$result){
        	$this->validationError('Member', _t('UpgradePage.USERNAME_INVALID', "The username is invalid"));
			$valid = false;
        } else {
        	$member = Distributor::get_obj_by_username($data['Member']);
        	$package = Package::get()->filter('Type', 'Upgrade')->filter('IsActive', 1)->byID((int)$data['PackageID']);
			if(!$package || $package->RestrictGroups()->byIDs($current_member->Groups()->getIDList())->count()){
				$this->validationError('Package', _t('UpgradePage.PACKAGE_INVALID', "Member package is invalid"));
				$valid = false;
			}
	        else if(!$package->Prices()->byID((int)$data['PriceID'])){
				$this->validationError('Package', _t('UpgradePage.PACKAGE_PRICE_INVALID', "Member package price is invalid"));
				$valid = false;
	        }
			else if(OrderPackage::get()->filter('MemberID', $member->ID)->filter('Status', 'Fully Paid')->filter('UpgradeGroup.Sort:GreaterThanOrEqual', $package->UpgradeGroup()->Sort)->count() > 0){
	        	$this->validationError('Package', _t('UpgradePage.INVALID_UPGRADE_PACKAGE', "The member is invalid to upgrade with these package"));
				$valid = false;
	        } 
        }

        // Execute the validators on the extensions
        if($this->extension_instances) {
            foreach($this->extension_instances as $extension) {
                if(method_exists($extension, 'hasMethod') && $extension->hasMethod('updatePHP')) {
                    $valid &= $extension->updatePHP($data, $this->form);
                }
            }
        }

        return $valid;
    }
}

class UpgradePayment_Validator extends Payment_Validator {

    protected $customRequired = array();

    /**
     * Constructor
     */
    public function __construct() {
        $required = func_get_args();
        if(isset($required[0]) && is_array($required[0])) {
            $required = $required[0];
        }
        $required = array_merge($required, $this->customRequired);

        parent::__construct($required);
    }

    /**
     * Check if the submitted list data is valid (server-side)
     *
     * @param array $data Submitted data
     * @return bool Returns TRUE if the submitted data is valid, otherwise
     *              FALSE.
     */
    function php($data) {
        $valid = parent::php($data);

		$current_member = Controller::curr()->CurrentMember();
		$obj = Sponsor::get()->find('MemberID', $current_member->ID);
		$member_id = Distributor::get_id_by_username($data['Member']);
    	$result = Sponsor::get()
    	->filter('NLeft:GreaterThanOrEqual', (int)$obj->NLeft)
    	->filter('NRight:LessThanOrEqual', (int)$obj->NRight)
		->filter('MemberID', (int)$member_id)->count();
		
		if(!$result){
        	$obj = Placement::get()->find('MemberID', $current_member->ID);
			$result = Placement::get()
	    	->filter('NLeft:GreaterThanOrEqual', (int)$obj->NLeft)
	    	->filter('NRight:LessThanOrEqual', (int)$obj->NRight)
			->filter('MemberID', (int)$member_id)->count();
        }
		
		if($result){
			$member = Member::get()->find('Username', $data['Member']);
			if($member->RegisterType == 'WithoutPayment'){
				$result = false;
			}
		}
		
        if(!$result){
        	$this->validationError('Member', _t('UpgradePage.USERNAME_INVALID', "The username is invalid"));
			$valid = false;
        } else {
        	$member = Distributor::get_obj_by_username($data['Member']);
        	$package = Package::get()->filter('Type', 'Upgrade')->filter('IsActive', 1)->byID((int)$data['PackageID']);
			if(!$package || $package->RestrictGroups()->byIDs($current_member->Groups()->getIDList())->count()){
				$this->validationError('Package', _t('UpgradePage.PACKAGE_INVALID', "Member package is invalid"));
				$valid = false;
			}
	        else if(!$package->Prices()->byID((int)$data['PriceID'])){
				$this->validationError('Package', _t('UpgradePage.PACKAGE_PRICE_INVALID', "Member package price is invalid"));
				$valid = false;
	        }
			else if(OrderPackage::get()->filter('MemberID', $member->ID)->filter('Status', 'Fully Paid')->filter('UpgradeGroup.Sort:GreaterThanOrEqual', $package->UpgradeGroup()->Sort)->count() > 0){
	        	$this->validationError('Package', _t('UpgradePage.INVALID_UPGRADE_PACKAGE', "The member is invalid to upgrade with these package"));
				$valid = false;
	        } 
        }

        // Execute the validators on the extensions
        if($this->extension_instances) {
            foreach($this->extension_instances as $extension) {
                if(method_exists($extension, 'hasMethod') && $extension->hasMethod('updatePHP')) {
                    $valid &= $extension->updatePHP($data, $this->form);
                }
            }
        }

        return $valid;
    }
}